package com.fary.channels.spi;

import com.fary.ch.FaryDefaultSelectorProvider;
import sun.misc.Service;
import sun.misc.ServiceConfigurationError;

import java.io.IOException;
import java.util.Iterator;

public abstract class FarySelectorProvider {

    private static final Object lock = new Object();
    private static FarySelectorProvider provider = null;

    /**
     * 获取SelectorProvider
     */
    public static FarySelectorProvider provider() {
        synchronized (lock) {
            if (provider != null)
                return provider;
            if (loadProviderFromProperty())
                return provider;
            if (loadProviderAsService())
                return provider;
            provider = FaryDefaultSelectorProvider.create();
            return provider;
        }
    }

    private static boolean loadProviderFromProperty() {
        String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");
        if (cn == null)
            return false;
        try {
            Class c = Class.forName(cn, true, ClassLoader.getSystemClassLoader());
            provider = (FarySelectorProvider) c.newInstance();
            return true;
        } catch (Exception x) {
            throw new ServiceConfigurationError(x);
        }
    }

    private static boolean loadProviderAsService() {
        Iterator<FarySelectorProvider> i = Service.providers(FarySelectorProvider.class, ClassLoader.getSystemClassLoader());
        for (;;) {
            try {
                if (!i.hasNext()) {
                    return false;
                }
                provider = i.next();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public abstract FaryAbstractSelector openSelector() throws IOException;

}